import Concurrent from "./Concurrent";
import { Toolkit } from "./Toolkit";
import Watcher from "./Watcher";
const { ccclass, property } = cc._decorator;




@ccclass("pool_object_data")
export class pool_object_data {

    @property(cc.Prefab)
    prefab: cc.Prefab = null;

    @property()
    initCount: number = 0;
}


@ccclass
export default class ObjectPool extends cc.Component {

    /** 对象池元素全部创建完成 */
    static readonly POOL_ELEMENT_CREATED = 'POOL_ELEMENT_CREATED';
    @property({ type: [pool_object_data] })
    private pool_element: pool_object_data[] = [];
    private elements: cc.Node[] = [];
    private objectPool: { [_: string]: cc.Node[] } = {};
    private static __instance: ObjectPool = null;
    public static get instance() {
        return ObjectPool.__instance;
    }

    onLoad() {
        const self = this;
        const startm = cc.director.getTotalTime();
        ObjectPool.__instance = this;

        const run = async () => {
            const concurrent = new Concurrent(10);
            for (let i = 0; i < this.pool_element.length; i++) {

                let object_config = this.pool_element[i];
                let key = object_config.prefab.name;
                let pool = self.objectPool[key] = [];

                let functor = function () {
                    for (let j = 0; j < object_config.initCount; j++) {

                        //console.log(`${object_config.prefab.name} ${j} / ${object_config.initCount}`);
                        let instance = cc.instantiate(object_config.prefab);
                        self.elements.push(instance);
                        pool.push(instance)
                    }
                };
                concurrent.add(functor);
            }

        };

        setTimeout(() => {
            run().then(() => {
                const endTime = cc.director.getTotalTime();
                console.log(`pool element create complete: ${endTime - startm} ms`);
                Watcher.dispatch(ObjectPool.POOL_ELEMENT_CREATED);
            });
        },1);
    }


    public spawn(key: string): cc.Node {

        if (key in this.objectPool) {

            let pool = this.objectPool[key];
            if (pool.length > 0) {
                let element = pool.shift();
                element.name = key;
                return element;
            }
        }
        else {

            Toolkit.logFailure(`${key}: object pool does not contain this`);
        }

        return null;
    }



    public despawn(obj: cc.Node) {

        (null != obj.parent) && obj.removeFromParent();
        let pool = this.objectPool[obj.name];
        pool && pool.push(obj);
    }


    public release() {

        for (let e of this.elements) {
            e.destroy();
        }

        this.elements = [];
        this.objectPool = {};
    }


}
